package org.wxd.bi.data;

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wxd.batis.EntityField;
import org.wxd.batis.sql.SqlDataWrapper;
import org.wxd.batis.sql.SqlEntityTable;
import org.wxd.batis.sql.mysql.MysqlDataHelper;
import org.wxd.collection.SplitCollection;
import org.wxd.threading.Work;
import org.wxd.threading.Worker;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据落库管理
 *
 * @author: Troy.Chen(無心道, 15388152619)
 * @version: 2021-10-25 09:34
 **/
@Resource
public class InnerDbWork implements Serializable, Worker {

    private static final long serialVersionUID = 1L;
    private static final Logger log = LoggerFactory.getLogger(InnerDbWork.class);

    @Resource
    private AppFactory appFactory;
    private Work[] works = null;
    /**
     * <p>key : appid
     * <p>value :
     * <p>----- key : 表名
     * <p>----- value : 数据
     */
    private LinkedHashMap<Integer, LinkedHashMap<SqlEntityTable, SplitCollection<JSONObject>>> innerMap = new LinkedHashMap<>();

    public InnerDbWork() {

    }

    public Work[] getWorks() {
        if (works == null) {
            newWorks(1);
        }
        return works;
    }

    public InnerDbWork newWorks(int workSize) {
        this.works = new Work[workSize];
        for (int i = 0; i < workSize; i++) {
            this.works[i] = new Work(this);
        }
        return this;
    }

    public void addInner(int appId, SqlEntityTable sqlEntityTable, JSONObject data) {
        synchronized (innerMap) {
            innerMap.computeIfAbsent(appId, l -> new LinkedHashMap<>())
                    .computeIfAbsent(sqlEntityTable, l -> new SplitCollection<>())
                    .add(data);
            getWorks();
        }
    }


    @Override
    public boolean isClose() {
        return Worker.super.isClose();
    }

    @Override
    public void job() throws Exception {
        Map.Entry<Integer, LinkedHashMap<SqlEntityTable, SplitCollection<JSONObject>>> next;
        synchronized (innerMap) {
            final Iterator<Map.Entry<Integer, LinkedHashMap<SqlEntityTable, SplitCollection<JSONObject>>>> iterator = innerMap.entrySet().iterator();
            if (iterator.hasNext()) {
                next = iterator.next();
                iterator.remove();
            } else {
                return;
            }
        }

        Integer appId = next.getKey();
        LinkedHashMap<SqlEntityTable, SplitCollection<JSONObject>> value = next.getValue();
        AppService appService = appFactory.dataService(appId);
        final MysqlDataHelper appDataHelper = appService.getAppDataHelper();
        final SqlDataWrapper<SqlEntityTable> sqlDataWrapper = appDataHelper.getDataWrapper();
        for (Map.Entry<SqlEntityTable, SplitCollection<JSONObject>> listEntry : value.entrySet()) {
            final SqlEntityTable entityTable = listEntry.getKey();
            final SplitCollection<JSONObject> datas = listEntry.getValue();
            while (!datas.isEmpty()) {
                List<JSONObject> replaceOneModels = datas.removeFrist();
                String replaceSql = entityTable.getReplaceSql(null);
                appDataHelper.stmtCum(
                        (stmt) -> {
                            for (JSONObject model : replaceOneModels) {
                                final Collection<EntityField> columns = entityTable.getColumns();
                                int index = 1;
                                for (EntityField column : columns) {
                                    Object o = model.get(column.getColumnName());
                                    sqlDataWrapper.setStmtParams(stmt, index, column, o);
                                    index++;
                                }
                                stmt.addBatch();
                                stmt.clearParameters();
                            }
                            stmt.executeBatch();
                        },
                        replaceSql
                );
            }
        }

    }

}
